﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.VersionControl;
using UnityEngine;
using Object = UnityEngine.Object;

namespace HXu.BaseTools
{
    /// <summary>
    /// DebugTools 打印输出工具 <br />
    /// /************************************************* <br />
    /// -- 内容：
    /// <br />
    ///     1A、Log。<br />
    ///     1B、LogWarning。<br />
    ///     1C、LogError。<br />
    /// <br />
    ///     2A、以固定格式输出集合、链表、字典元素。<br />
    /// <br />
    /// -- 使用方法：
    /// <br />
    ///     1、引用命名空间，直接调用。<br />
    /// *************************************************/ <br />
    /// </summary>

    public static class DebugTools
    {
        // 控制是否启用日志输出
        private static bool UseLog = true;

        #region API

        /// <summary>
        /// 1A、Log - 输出普通日志
        /// </summary>
        /// <param name="context">上下文对象（通常为 MonoBehaviour 或 ScriptableObject）</param>
        /// <param name="message">日志内容</param>
        public static void Log(this Object context, object message)
        {
            if (UseLog)
            {
                var info = FormatLog("HXuLog_Normal", message);
                Debug.Log(info);
            }
        }

        /// <summary>
        /// 1A、Log - 输出普通日志（无上下文）
        /// </summary>
        /// <param name="message">日志内容</param>
        public static void Log(this object message)
        {
            if (UseLog)
            {
                var info = FormatLog("HXuLog_Normal", message);
                Debug.unityLogger.Log(LogType.Log, info);
            }
        }

        /// <summary>
        /// 1B、LogWarning - 输出警告日志
        /// </summary>
        /// <param name="context">上下文对象</param>
        /// <param name="message">日志内容</param>
        public static void LogWarning(this Object context, object message)
        {
            if (UseLog)
            {

                
                var warningInfo = FormatLog("HXuLog_Warning", message);
                Debug.unityLogger.Log(LogType.Warning, warningInfo);
            }
        }

        /// <summary>
        /// 1B、LogWarning - 输出警告日志（无上下文）
        /// </summary>
        /// <param name="message">日志内容</param>
        public static void LogWarning(this object message)
        {
            if (UseLog)
            {
                var warningInfo = FormatLog("HXuLog_Warning", message);
                Debug.unityLogger.Log(LogType.Warning, warningInfo);
            }
        }

        /// <summary>
        /// 1C、LogError - 输出错误日志
        /// </summary>
        /// <param name="context">上下文对象</param>
        /// <param name="message">日志内容</param>
        public static void LogError(this Object context, object message)
        {
            if (UseLog)
            {
                
                var errorInfo = FormatLog("HXuLog_Error", message);
                Debug.unityLogger.Log(LogType.Error, errorInfo);
            }
        }

        /// <summary>
        /// 1C、LogError - 输出错误日志（无上下文）
        /// </summary>
        /// <param name="message">日志内容</param>
        public static void LogError(this object message)
        {
            if (UseLog)
            {
                var errorInfo = FormatLog("HXuLog_Error", message);
                Debug.unityLogger.Log(LogType.Error, errorInfo);
            }
        }

        /// <summary>
        /// 2A、以固定格式输出数组元素
        /// </summary>
        /// <param name="values">数组</param>
        /// <param name="separator">分隔符（默认为 " - "）</param>
        public static void LogJoin(this object[] values, string separator = " - ")
        {
            if (UseLog)
            {
                var info = FormatLog("HXuLog_Join", string.Join(separator, values));
                Debug.unityLogger.Log(LogType.Log, info);
            }
        }

        /// <summary>
        /// 2A、以固定格式输出集合、链表、字典元素
        /// </summary>
        /// <param name="values">集合</param>
        /// <param name="separator">分隔符（默认为 " - "）</param>
        public static void LogJoin<T>(this IEnumerable<T> values, string separator = " - ")
        {
            if (UseLog)
            {
                var info = FormatLog("HXuLog_Join", string.Join(separator, values));
                Debug.unityLogger.Log(LogType.Log, info);
            }
        }

        #endregion

        #region Private  

        // 日志文件路径
        private static string fullPath;

        // 防止重复打开文件的标志
        private static bool m_hasForceMono;

        /// <summary>
        /// 格式化日志信息
        /// </summary>
        /// <param name="prefix">日志前缀，通常用于标识日志的来源或类型</param>
        /// <param name="message">日志内容，可以是任意类型的对象</param>
        /// <returns>格式化后的日志字符串</returns>
        private static string FormatLog(string prefix, object message)
        {
            // 格式为：[前缀]：消息内容
            return $"[{prefix}]：{message}";
        }

        /// <summary>
        /// 初始化日志系统
        /// </summary>
        public static void InitLogger()
        {
            //定义日志文件路径
            fullPath = Application.dataPath + "/output.txt";
            //检查并删除已存在的日志文件
            if (File.Exists(fullPath)) File.Delete(fullPath);
            //检查日志文件所在的目录是否存在
            if (Directory.Exists(fullPath.Replace("/output.txt", "")))
            {
                //创建日志文件并注册日志回调
                FileStream fs = File.Create(fullPath);
                fs.Close();
                Application.logMessageReceived += logCallBack;
            }
            else
            {
                //处理目录不存在的情况
                Debug.LogError("directory is not exist");
            }
        }

        /// <summary>
        /// 日志回调函数，将日志写入文件
        /// </summary>
        /// <param name="condition">日志内容</param>
        /// <param name="stackTrace">堆栈信息</param>
        /// <param name="type">日志类型</param>
        private static void logCallBack(string condition, string stackTrace, LogType type)
        {
            if (File.Exists(fullPath))
            {
                using (StreamWriter sw = File.AppendText(fullPath))
                {
                    sw.WriteLine(condition);
                    sw.WriteLine(stackTrace);
                }
            }
        }

        /// <summary>
        /// 设置是否启用日志输出
        /// </summary>
        /// <param name="use">是否启用</param>
        public static void SetUseDebuger(bool use)
        {
            UseLog = use;
        }


#if UNITY_EDITOR
       
        // 处理Asset打开的Callback函数
        [UnityEditor.Callbacks.OnOpenAsset(-1)]
        static bool OnOpenAsset(int instance, int line) 
        {
            if (m_hasForceMono) return false;

            // 获取当前日志的堆栈信息
            string stack_trace = GetStackTrace();
            // 通过堆栈信息判断是否是我们自定义的日志
            if (!stack_trace.IsNullOrEmpty() && (stack_trace.Contains("[HXuLog_Normal]：") || stack_trace.Contains("[HXuLog_Join]：") || stack_trace.Contains("[HXuLog_Warning]：") || stack_trace.Contains("[HXuLog_Error]：")))
            {
                // 使用正则表达式匹配文件路径和行号
                Match matches = Regex.Match(stack_trace, @"\(at (.+)\)", RegexOptions.IgnoreCase);
                while (matches.Success)
                {
                     string pathline = matches.Groups[1].Value;

                    // 找到不是我们自定义log文件的那行，重新整理文件路径，手动打开
                    // 排除DebugTools.cs文件本身
                    var pathStr = pathline.Split('/')[pathline.Split('/').Length - 1].Split(':')[0];

                    if (!pathline.IsNullOrEmpty() && !pathStr.Equals("DebugTools.cs"))
                    {
                        var path = pathline.Split(':')[0];
                        line = Convert.ToInt32(pathline.Split(':')[1]);
                        m_hasForceMono = true;
                        // 方式一：通过AssetDatabase打开文件并定位到指定行
                        AssetDatabase.OpenAsset(AssetDatabase.LoadAssetAtPath<Object>(path), line);
                        m_hasForceMono = false;
                        //string fullpath = Application.dataPath.Substring(0, Application.dataPath.LastIndexOf("Assets"));
                        // fullpath = fullpath + path;
                        //  UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal(fullpath.Replace('/', '\\'), line);
                        return true;
                    }
                    matches = matches.NextMatch();
                }
                return true;
            }
            return false;
        }
        
        /// <summary>
        /// 获取当前日志的堆栈信息
        /// </summary>
        /// <returns>堆栈信息</returns>
        static string GetStackTrace()
        {
            // 反射获取UnityEditor.ConsoleWindow类
            var type_console_window = typeof(EditorWindow).Assembly.GetType("UnityEditor.ConsoleWindow");
            // 获取ConsoleWindow的静态字段ms_ConsoleWindow
            var filedInfo = type_console_window.GetField("ms_ConsoleWindow", BindingFlags.Static | BindingFlags.NonPublic);
            // 获取ms_ConsoleWindow的值
            if (filedInfo != null)
            {
                var ConsoleWindowInstance = filedInfo.GetValue(null);
                if (ConsoleWindowInstance != null)
                {
                    if (EditorWindow.focusedWindow == (EditorWindow)ConsoleWindowInstance)
                    {
                        // 获取ConsoleWindow的实例字段m_ActiveText
                        filedInfo = type_console_window.GetField("m_ActiveText", BindingFlags.Instance | BindingFlags.NonPublic);
                        if (filedInfo != null)
                        {
                            string activeText = filedInfo.GetValue(ConsoleWindowInstance).ToString();
                            return activeText;
                        }
                    }
                }
            }

            return null;
        }
#endif
        #endregion  
    }
}
